#include <iostream>
#include "tlistaporo.h"
#include "tporo.h"
using namespace std;

/** \file tlistaporo.cpp
* \brief Procedimientos de la clase TListaPoro.
*
* STANISLAV LITVINENKO DNI:02062226T
* JOSÉ FRANCÉS IRIONDO DNI:48469642V
*/

TListaNodo::TListaNodo()
{
	anterior=NULL;
	siguiente=NULL;
}
TListaNodo::TListaNodo(const TListaNodo& nodo)
{
	e=nodo.e;
	anterior=nodo.anterior;
	siguiente=nodo.siguiente;
}
TListaNodo::~TListaNodo()
{
	anterior=NULL;
	siguiente=NULL;
}
TListaNodo & TListaNodo::operator=(const TListaNodo &nodo)
{
	if(this != &nodo)
	{
		e = nodo.e;
		anterior = nodo.anterior;
		siguiente = nodo.siguiente;
	}
}
TListaPosicion::TListaPosicion()
{
	pos=NULL;
}

TListaPosicion::~TListaPosicion()
{
	pos=NULL;
}

TListaPosicion &TListaPosicion::operator=(const TListaPosicion &lp)
{
	if(this!=&lp)
		pos=lp.pos;

	return *this;
}

TListaPosicion::TListaPosicion(const TListaPosicion &lp)
:pos(lp.pos)
 {}

bool TListaPosicion::operator==(const TListaPosicion &lp) const
{
	return pos==lp.pos;
}

bool TListaPosicion::EsVacia()
{
	return pos==NULL;
}

TListaPosicion TListaPosicion::Anterior()
{
	TListaPosicion auxiliarP;

	if(pos!=NULL)
		auxiliarP.pos=pos->anterior;

	return auxiliarP;
}

TListaPosicion TListaPosicion::Siguiente()
{
	TListaPosicion auxiliarP;

	if(pos!=NULL)
		auxiliarP.pos=pos->siguiente;

	return auxiliarP;
}

TListaPoro::TListaPoro()
{
	primero=ultimo=NULL;
}

TListaPoro::TListaPoro(const TListaPoro &p)
{
	primero=ultimo=NULL;
	*this=p;
}

TListaPoro::~TListaPoro()
{
	TListaNodo *ptB, *ptL;

	ptL=primero;

	while(ptL)
	{
		ptB=ptL;
		ptL=ptL->siguiente;
		delete ptB;
	}
	primero=ultimo=NULL;
}
int TListaPoro::Longitud()const
{
	int n;
	TListaNodo *ptL;

	n=0;
	ptL=primero;

	while(ptL)
	{
		ptL=ptL->siguiente;
		n++;
	}
	return n;
}
TListaPoro &TListaPoro::operator=(const TListaPoro &lp)
{
	TListaNodo *ptL;
	if(this!=&lp)
	{
		this->~TListaPoro();
		ptL=lp.primero;
		while(ptL)
		{
			Insertar(ptL->e); 
			ptL=ptL->siguiente;
		}
	}
	return *this;
}

bool TListaPoro::operator==(const TListaPoro &lp) const
{
	TListaNodo *ptLUno, *ptLDos;
	bool iguales;
	int longitud=0,longitudaux=0;

	longitud=Longitud();
	longitudaux=lp.Longitud();
	if(longitud != longitudaux)
	{
		iguales=false;
	}
	else
	{
		ptLUno=primero;
		ptLDos=lp.primero;
		iguales=true;
		while(ptLUno!=NULL && ptLDos!=NULL && iguales)
		{
			if(ptLUno->e != ptLDos->e)
			{
				iguales=false;
			}
			else
			{
				ptLUno=ptLUno->siguiente;
				ptLDos=ptLDos->siguiente;
			}
		}
	}
	return iguales;
}

TListaPoro TListaPoro::operator+(const TListaPoro &lp) const
{
	TListaPoro aux(*this);
	//TListaPoro aux;
	//TListaNodo *ptL;
	TListaPosicion e;

	//if(!lp.EsVacia())
	//{
		for(e.pos = lp.primero; e.pos != NULL; e.pos = e.pos->siguiente)
		{
			aux.ultimo->siguiente = new TListaNodo(*e.pos);
			aux.ultimo->siguiente->anterior = aux.ultimo;
			aux.ultimo = aux.ultimo->siguiente;
		}
	//}
	return aux;

	/*ptL=lp.primero;
	while(ptL)
	{
		aux.Insertar(ptL->e);
		ptL=ptL->siguiente;
	}
	return aux;
	*/
}

TListaPoro TListaPoro::operator-(const TListaPoro &lp) const
{
	TListaPoro auxiliar;
	TListaNodo *ptL;
	
	ptL=primero;

	while(ptL)
	{
		if(!lp.Buscar(ptL->e))
			auxiliar.Insertar(ptL->e);
		ptL=ptL->siguiente;
	}
	return auxiliar;
}

bool TListaPoro::EsVacia()
{
	return primero=ultimo=NULL;
}

bool TListaPoro::Insertar(const TPoro &p)
{
	TListaPosicion e;
	TListaNodo nodo;
	bool ret,insertado=false;

	nodo.e = p;

	if(primero == NULL)
	{
		ultimo = primero = new TListaNodo(nodo);
	}
	else
	{
		for(e.pos = primero;insertado==false && e.pos!=NULL; e.pos=e.pos->siguiente)
		{
			if(e.pos->e.Volumen()>nodo.e.Volumen())//insertamos en la izquierda
			{
				if(e.pos->anterior==NULL)
				{
					e.pos->anterior = new TListaNodo(nodo);
					if(e.pos->anterior!=NULL)
					{
						ret=true;
						insertado=true;
						e.pos->anterior->siguiente = e.pos;
					}
					primero = e.pos->anterior;
				}
				else
				{
					TListaPosicion aux;
					aux.pos = e.pos->anterior;
					e.pos->anterior = new TListaNodo(nodo);
					if(e.pos->anterior !=NULL)
					{
						ret=true;
						insertado=true;
						e.pos->anterior->siguiente = e.pos;
						e.pos->anterior->anterior = aux.pos;
						aux.pos->siguiente = e.pos->anterior;
					}
					aux.pos  = NULL;
				}
			}
			else  //insertamos en la derecha
			{
				if(e.pos->siguiente ==NULL)
				{
					e.pos->siguiente = new TListaNodo(nodo);
					if(e.pos->siguiente!=NULL)
					{
						ret=true;
						insertado=true;
						e.pos->siguiente->anterior = e.pos;
						e.pos->siguiente->siguiente = NULL;
					}
					ultimo = e.pos->siguiente;
				}
				else
				{
					if(e.pos->siguiente->e.Volumen()>nodo.e.Volumen())
					{

					
						TListaPosicion aux;
						aux.pos = e.pos->siguiente;
						e.pos->siguiente = new TListaNodo(nodo);
						if(e.pos->siguiente != NULL)
						{
							ret=true;
							insertado=true;
							e.pos->siguiente->anterior = e.pos;
							e.pos->siguiente->siguiente = aux.pos;
							aux.pos->anterior = e.pos->siguiente;
						}
						aux.pos=NULL;
					}
				}
			}
		}
	}

	return ret;
/*
	TListaNodo *ptA, *ptL;
	bool mayor, enc;

	ptA=NULL;
	ptL=primero;
	enc=false;
	mayor=false;

	while(ptL && !enc && !mayor)
	{
		if(ptL->e.Volumen()==p.Volumen())
		{
			enc=true;
		}
		else if(p.Volumen()>ptL->e.Volumen())
		{
			mayor=true;
		}
		else
		{
			ptA=ptL;
			cout << "HI" <<endl;
			ptL=ptL->siguiente;
		}
	}
	if(!enc)
	{
		TListaNodo* ptN=new TListaNodo;
		ptN->e=p;
		if(ptA==NULL)
		{		
			primero=ptN;
		}
		else
		{
			ptA->siguiente=ptN;
		}
		if(ptL==NULL)
		{
			ultimo=ptN;
		}
		else
		{
			ptL->anterior=ptN;
		}

	}
		return !enc;
*/
}

bool TListaPoro::Borrar(const TPoro &p)
{
	bool enc, mayor;
	TListaNodo *ptA, *ptL;

	ptA=NULL;
	ptL=primero;
	enc=false;
	mayor=false;

	while(ptL && !enc && !mayor) //Recorremos la lista mientras no sea el ultimo elemento, ni lo hayamos encontrado ni sea mayor.
	{
		if(ptL->e==p)
			enc=true;
		//else if(ptL->e>p)
		else if(ptL->e.Volumen() > p.Volumen())
		{
			mayor=true;
		}
		else
		{
			ptA=ptL;
			ptL=ptL->siguiente;
		}
	}

	if(enc) // Si se ha encontrado.
	{
		if(ptL==primero)
			primero=primero->siguiente;
		else
			ptA->siguiente=ptL->siguiente;
		if(ptL==ultimo)
			ultimo=ultimo->anterior;
		else
			ptL->siguiente->anterior=ptL->anterior;
	}
	delete ptL;
	return enc;
}

bool TListaPoro::Borrar(TListaPosicion &p)
{
	bool borrado=false, encontrado;
	TListaNodo *ptL, *ptA, *ptB;
	ptA=primero;
	ptB=ultimo;

	if(!p.EsVacia())
	{
		encontrado=false;
		ptL=primero;
		while(ptL && !encontrado)
		{
			if(ptL!=p.pos)
			{
				ptL=ptL->siguiente;
			}
			else
			{
				encontrado=true;
			}
		}
		if(encontrado)
		{
			if(p.pos->anterior == NULL)
			{
				primero = primero->siguiente;
				if(primero!=NULL)
				{
					primero->anterior = NULL;
				}
			}
			else if(p.pos->siguiente == NULL)
			{
				ultimo = ultimo->anterior;
				if(ultimo!=NULL)
				{
					ultimo->siguiente=NULL;
				}
			}
			else
			{
				p.pos->anterior->siguiente=p.pos->siguiente;
				p.pos->siguiente->anterior=p.pos->anterior;
			}
			p.pos->anterior=NULL;
			p.pos->siguiente=NULL;
			delete p.pos;
			/*if(p.pos!=ptB)
				p.pos->siguiente->anterior=p.pos->anterior;
			else
				ptB=ptB->anterior;
			if(p.pos!=ptA)
				p.pos->anterior->siguiente=p.pos->siguiente;
			else
				ptA=ptA->siguiente;
			borrado=true;
			delete p.pos;
			p.pos=NULL;*/
			
		}
	}
	return borrado;
}

TPoro TListaPoro::Obtener(const TListaPosicion &lp) const
{
	bool encontrado=false;
	TPoro auxiliar;
	TListaNodo *ptL=primero;

	while(ptL && !encontrado)
	{
		if(ptL!=lp.pos)
			ptL=ptL->siguiente;
		else
			encontrado=true;
	}
	if(encontrado)
		auxiliar=lp.pos->e;

	return auxiliar;
}

bool TListaPoro::Buscar(const TPoro &p) const
{
	bool enc;
	TListaNodo *ptL;
	enc=false;
	ptL=primero;
	while(ptL && !enc)
	{
		if(ptL->e==p)
			enc=true;
		else
			ptL=ptL->siguiente;
	}
	return enc;
}



TListaPosicion TListaPoro::Primera()
{
	TListaPosicion principio;

	principio.pos=primero;

	return principio;
}

TListaPosicion TListaPoro::Ultima()
{
	TListaPosicion final;

	final.pos=ultimo;

	return final;
}
ostream& operator<<(ostream & os, const TListaPoro &l)
{
	TListaPosicion e;
	bool espacio=false;
	os << '(';

	if(l.primero != NULL)
	{
		for(e.pos = l.primero; e.pos!=NULL; e.pos=e.pos->siguiente)
		{
			if(espacio)
			{
				os << ' ';
			}
			os << e.pos->e;
			espacio=true;
		}
	}
	os << ')';
	return os;
}
